package com.umeox.recorder;

import android.annotation.SuppressLint;
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.umeox.moto.common.utils.FileUtils;
import com.umeox.moto.watch.themes.util.Stopwatch;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

public class Recorder {

    private static final int WHAT = 100;
    private MediaRecorder mMediaRecorder;
    private static final String TAG = "Recorder";
    private long mStartMillis;
    private String mFilePath;
    private final Stopwatch mStopwatch;
    private boolean mIsRunning;
    public static final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);

    private Recorder() {
        mStopwatch = Stopwatch.createUnstarted();
    }

    public synchronized void start() {
        try {
            mIsRunning = true;
            mStartMillis = System.currentTimeMillis();
            String fileName = mDateFormat.format(mStartMillis) + ".amr";
            mFilePath = FileUtils.getAppRecorderCache() + "/" + fileName;
            mMediaRecorder = new MediaRecorder();
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            mMediaRecorder.setOutputFile(mFilePath);
            mMediaRecorder.prepare();
            mMediaRecorder.start();
            mStopwatch.reset();
            mStopwatch.start();
            mUpdateTimeHandler.sendEmptyMessage(WHAT);
        } catch (IOException e) {
            Log.i("Recorder", "start", e);
            if (mRecordListener != null) {
                mRecordListener.onError(e);
            }
        }
    }

    public synchronized void stop() {
        try {
            mIsRunning = false;
            if (mMediaRecorder != null) {
                mMediaRecorder.stop();
                mMediaRecorder.release();
                mMediaRecorder = null;
            }
            mUpdateTimeHandler.removeCallbacksAndMessages(null);
            mStopwatch.stop();
            if (mRecordListener != null) {
                final long duration = mStopwatch.elapsed(TimeUnit.MILLISECONDS);
                mRecordListener.onComplete(mFilePath, mStartMillis, duration);
                Log.d(TAG, "stop FilePath:" + mFilePath + " duration:" + duration);
            }
        } catch (Exception e) {
            Log.e(TAG, "stop: ", e);
        }

    }

    public void release() {
        try {
            if (mMediaRecorder != null) {
                mMediaRecorder.stop();
                mMediaRecorder.release();
                mMediaRecorder = null;
                mIsRunning = false;
            }
        } catch (Exception e) {
            Log.e(TAG, "Recorder&release", e);
        }

        mUpdateTimeHandler.removeCallbacksAndMessages(null);
    }

    public void setOnRecorderListener(OnRecorderListener recordListener) {
        mRecordListener = recordListener;
    }

    private OnRecorderListener mRecordListener;

    /**
     * 录音是否正在运行
     *
     * @return
     */
    public boolean isRunning() {
        return mIsRunning;
    }

    public interface OnRecorderListener {
        void onComplete(String filePath, long startMillis, long duration);

        void onUpdate(long duration);

        void onError(IOException e);

    }

    public static Recorder getInstance() {
        return InstanceHolder.instance;
    }

    private static class InstanceHolder {
        private final static Recorder instance = new Recorder();
    }

    private static final long INTERACTIVE_UPDATE_RATE_MS = TimeUnit.MILLISECONDS.toMillis(100);
    @SuppressLint("HandlerLeak")
    private final Handler mUpdateTimeHandler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            if (WHAT == message.what) {
                mRecordListener.onUpdate(mStopwatch.elapsed(TimeUnit.MILLISECONDS));
                mUpdateTimeHandler.sendEmptyMessageDelayed(WHAT, INTERACTIVE_UPDATE_RATE_MS);
            }
        }
    };
}
